home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / GameKit / gamekit-1 / PreferencesBrain.m < prev    next >
Text File  |  1995-06-12  |  18KB  |  563 lines

  1.  
  2. /* Generated by Interface Builder */
  3.  
  4. #import <daymisckit/daymisckit.h>
  5. #import <gamekit/gamekit.h>
  6. #import <stdio.h>
  7. #import <stdlib.h>        /* malloc */
  8.  
  9. BOOL getBOOLPreference(const char *name, BOOL def)
  10. {
  11.     const char *tmpstr = NXGetDefaultValue ([NXApp appName], name);
  12.     int temp = def;
  13.     if (tmpstr) sscanf(tmpstr, "%d", &temp);
  14.     if (temp) return YES;
  15.     return NO;
  16. }
  17.  
  18. int getIntPreference(const char *name, int min, int max, int def)
  19. {
  20.     int tempInt;
  21.     const char *tmpstr = NXGetDefaultValue ([NXApp appName], name);
  22.     if (!tmpstr) return def;
  23.     else {
  24.         sscanf(tmpstr, "%d", &tempInt);
  25.         if (tempInt < min) return min;
  26.         if (tempInt > max) return max;
  27.     }
  28.     return tempInt;
  29. }
  30.  
  31. const char *getStringPreference(const char *name, const char *def)
  32. {
  33.     const char *tmpstr = NXGetDefaultValue ([NXApp appName], name);
  34.     if (tmpstr == NULL) return def;
  35.     return tmpstr; 
  36. }
  37.  
  38. void putIntPreference(const char *name, int value)
  39. {
  40.     char str[16];
  41.     sprintf(str, "%d", value);
  42.     NXWriteDefault ([NXApp appName], name, str);
  43. }
  44.  
  45. void putBOOLPreference(const char *name, BOOL value)
  46. {
  47.     char str[16];
  48.     int tempInt = 0;
  49.     if (value) tempInt = 1;
  50.     sprintf(str, "%d", tempInt);
  51.     NXWriteDefault ([NXApp appName], name, str);
  52. }
  53.  
  54. void putStringPreference(const char *name, const char *value)
  55. {
  56.     NXWriteDefault ([NXApp appName], name, value);
  57. }
  58.  
  59. @implementation PreferencesBrain
  60.  
  61. static char *defaultServer = "*";  // very slow -- subclass should override!
  62.  
  63. - init        // designated initializer sets up game variables
  64. {        // to sensible values.
  65.     int i;
  66.     
  67.     [super init];
  68.     for (i=0; i<MAXKEYS; i++) {    // get space to store default keypresses in
  69.         keys[i] = malloc(8);
  70.         defkey[i] = malloc(8);
  71.     }
  72.     numKeys = 5;
  73.     strcpy(defkey[0], "a");
  74.     strcpy(defkey[1], "z");
  75.     strcpy(defkey[2], "l");
  76.     strcpy(defkey[3], ";");
  77.     strcpy(defkey[4], " ");
  78.     defaultPlayerName = [[DAYString alloc] init];
  79.     version = malloc(8);
  80.     serverName = NXCopyStringBufferFromZone(defaultServer, [self zone]);
  81.     firstLoad = YES;
  82.     
  83.     return self;
  84. }
  85.  
  86. - appDidInit:sender    // forwarded by GameBrain
  87. {    // Do all our basic init here
  88.     if (!gameBrain) gameBrain = [NXApp delegate];
  89.     if (!info) info = [gameBrain infoController];
  90.     if (!scorePlayer) scorePlayer = [gameBrain scorePlayer];
  91.     if (!soundPlayer) soundPlayer = [gameBrain soundPlayer];
  92.     if (!highScoreTable)
  93.         highScoreTable = [gameBrain highScoreController];
  94.     if (!strings) strings = [gameBrain mainStrings];
  95.     if (!gameScreen) gameScreen = [gameBrain gameScreen];
  96.     [self readDefaults:self];
  97.     [gameScreen getPreferences];
  98.     return self;
  99. }
  100.  
  101. // methods to get at instance variables
  102. - (int)startLevel { return level; }    // returns starting level
  103. - (int)speed { return speed; }
  104. - (BOOL)border { return border; }  // return YES if gray border is on
  105. - (BOOL)effects { return effects; }
  106. - (BOOL)music { return music; }
  107. - (BOOL)alert { return alert; }
  108. - (BOOL)autoUnPause { return autoUnPause; }
  109. - (BOOL)autoStart { return autoStart; }
  110. - (BOOL)demoSound { return demoSound; }
  111. - (BOOL)useServer { return useServer; }
  112. - setAlert:(BOOL)al { alert = al; return self; }
  113. - setAutoUnPause:(BOOL)al { autoUnPause = al; return self; }
  114. - setAutoStart:(BOOL)al { autoStart = al; return self; }
  115. - (const char *)serverName { return serverName; }
  116. - setNumKeys:(int)num { numKeys = num; return self; }
  117.  
  118. - readDefaults:sender        // get preferences from defaults database
  119. {
  120.     char *tmpstr = malloc(16);
  121.     int i;
  122.     
  123.     if (serverName) free(serverName);
  124.     useServer    = getBOOLPreference("UseServer", NO);
  125.     effects        = getBOOLPreference("SoundOn", YES);
  126.     alert        = getBOOLPreference("Alerts", YES);
  127.     autoUnPause    = getBOOLPreference("AutoUnPause", YES);
  128.     autoStart    = getBOOLPreference("AutoStart", YES);
  129.     border        = getBOOLPreference("Border", YES);
  130.     demoSound    = getBOOLPreference("DemoSound", YES);
  131.     music        = getBOOLPreference("MusicOn", YES);
  132.     level        = getIntPreference("StartLevel", 1, 20, 1);
  133.     speed        = getIntPreference("GameSpeed", 0, 2, 1);
  134.     
  135.     serverName    = NXCopyStringBufferFromZone(
  136.             getStringPreference("ServerName", defaultServer), [self zone]);
  137.     strcpy(version, getStringPreference("Version", "0.0"));
  138.     [self setDefaultPlayerName:getStringPreference(
  139.             "PlayerName", [NXApp userRealName])];
  140.     for (i=0; i < numKeys; i++) {
  141.         sprintf(tmpstr, "Key%d", i);
  142.         strcpy(keys[i], getStringPreference(tmpstr, defkey[i]));
  143.         [gameScreen setKey:i val:keys[i][0]];    
  144.     }
  145.     
  146.     [gameScreen getPreferences];
  147.     [highScoreTable setServerHost:serverName];
  148.     if (useServer) [highScoreTable setLocalScores:NO];
  149.     else [highScoreTable setLocalScores:YES];
  150.     // if couldn't locate the server, go local.
  151.     if (useServer && [highScoreTable localScores]) useServer = NO;
  152.     free(tmpstr);
  153.     [soundPlayer turnOn:effects];
  154.     return self;
  155. }
  156.  
  157. - writeDefaults:sender        // save preferences in defaults database
  158. {
  159.     char str[32]; int i;
  160.     
  161.     putBOOLPreference    ("Border",        border);
  162.     putBOOLPreference    ("Alerts",        alert);
  163.     putBOOLPreference    ("AutoStart",    autoStart);
  164.     putBOOLPreference    ("AutoUnPause",    autoUnPause);
  165.     putBOOLPreference    ("DemoSound",    demoSound);
  166.     putBOOLPreference    ("MusicOn",        music);
  167.     putBOOLPreference    ("SoundOn",        effects);
  168.     putBOOLPreference    ("UseServer",    useServer);
  169.     putIntPreference    ("GameSpeed",    speed);
  170.     putIntPreference    ("StartLevel",    level);
  171.     putStringPreference    ("Version",        version);
  172.     putStringPreference    ("ServerName",    serverName);
  173.     putStringPreference    ("PlayerName",    [defaultPlayerName stringValue]);
  174.     
  175.     for (i=0; i<numKeys; i++) { // ***** it would be better to make a single
  176.         // string for all the keys; in the future I might make this adjustment.
  177.         // This method leaves quite a few defaults...
  178.         sprintf(str, "Key%d", i);
  179.         putStringPreference(str, keys[i]);
  180.     }
  181.     return self;
  182. }
  183.  
  184. - (BOOL)firstTimeCheck // first time running this version?
  185. {
  186.     if (!version || ![info versionString]) return NO; // if NULL, then this
  187.         // mechanism is disabled, so it's NEVER the first time running...
  188.     if (strcmp(version, [info versionString])) { // first time if !=
  189.         strcpy(version, [info versionString]);
  190.         return YES; // when the Prefs are saved (exit, etc.) the version
  191.         // # will be stored in defaults and then next time we'll return a NO
  192.     }
  193.     return NO;
  194. }
  195.  
  196. - revert:sender    // return to default values
  197. {
  198.     int tempInt;
  199.  
  200.     speed = 1; effects = YES; alert = YES;
  201.     autoUnPause = YES; autoStart = YES; border = YES;
  202.     demoSound = YES; music = YES; useServer = NO;
  203.     if (serverName) free(serverName);
  204.     serverName = NXCopyStringBufferFromZone(defaultServer, [self zone]);
  205.     if (![highScoreTable localScores]) [highScoreTable closeServers];
  206.     [highScoreTable setServerHost:serverName];
  207.     [gameScreen revertBackground:sender];
  208.     for (tempInt=0; tempInt<numKeys; tempInt++) {
  209.         strcpy(keys[tempInt], defkey[tempInt]);
  210.     }
  211.     // I'm not reverting defaultPlayerName; doesn't seem necessary
  212.     
  213.     for (tempInt=0; tempInt<4; tempInt++)
  214.         [gameScreen setKey:tempInt val:keys[tempInt][0]]; 
  215.     [gameScreen getPreferences];   // make sure that the gameScreen is aware
  216.     return [self preferences:self]; // update the panel
  217. }
  218.  
  219. - takeKey:sender           // used by below (keyChange) to get new keys
  220. { // This is klunky; there's a better way to fill up the matrix; I'll
  221.     // fix it eventually ***** (See how the GKHighScorePanel does it; it's
  222.     // much cleaner than this.)
  223.     strcpy(keys[[sender tag]],[sender stringValue]);    // store internally
  224.     [gameScreen setKey:[sender tag] val:keys[[sender tag]][0]]; // send to view
  225.     return self;
  226. }
  227.  
  228. - (char)keyVal:(int)keyIndex    // returns default key for action (0-4)
  229. { return keys[keyIndex][0]; }
  230.  
  231. - keyChange:sender            // accept changes in keys
  232. {
  233.     [keyMatrix sendAction:@selector(takeKey:) to:self forAllCells:YES];
  234.     // ***** I should check here to be sure that the new keys don't
  235.     // conflict with each other or with the 'p' and 'n' keys...
  236.     return self;
  237. }
  238.  
  239. - changeLevel:sender
  240. {
  241.     level = [sender intValue];
  242.     if (sender != levelSlider) [levelSlider setIntValue:level];
  243.     else [levelText setIntValue:level];
  244.     return self;
  245. }
  246.  
  247. - speedChange:sender            // accept changes in speed
  248. {
  249.     speed = [sender selectedTag];
  250.     return self;
  251. }
  252.  
  253.  
  254. - findKeyFor:sender        // used by below to set keys in pref. matrix
  255. {
  256.     [sender setStringValue:keys[[sender tag]]];
  257.     return self;
  258. }
  259.  
  260. - setUpViews
  261. {    // here is where we hook up the views to be switched around in the panel
  262.     // you should override this to add extra panes besides the three basic
  263.     // ones expected here; you can use Columns as an example of how you
  264.     // would go about doing this.
  265.     [inspectorBox getFrame:&inspectFrame];
  266.     [viewPlayer getFrame:&view[0]];
  267.     [viewScreen getFrame:&view[1]];
  268.     [viewSound  getFrame:&view[2]];
  269.     ViewsList = [[List alloc] init];
  270.     thePopUpList = [thePopUpListButton target];
  271.     [thePopUpList setTarget:self];
  272.     [thePopUpList setAction:@selector(toggleInspectorPanels:)];
  273.     [thePopUpList removeItemAt:0];  
  274.     [thePopUpList removeItemAt:0];  
  275.     [thePopUpList removeItemAt:0];      
  276.     [[[[self
  277.         addView:viewPlayer withName:[strings valueForStringKey:"Player"]]
  278.         addView:viewScreen withName:[strings valueForStringKey:"Screen"]]
  279.         addView:viewSound  withName:[strings valueForStringKey:"Sound" ]]
  280.         show:[strings valueForStringKey:"Player"]];
  281.     [preferencesPanel orderFront:self];
  282.     [inspectorBox display];
  283.     return self;
  284. }
  285.  
  286. - preferences:sender        // sets controls on pref panel & brings it up
  287. {
  288.     [self preferencesPanel]; // be sure panel is loaded; throw away return val.
  289.     if (firstLoad) {
  290.         [self setUpViews];
  291.         [preferencesPanel orderFront:self];
  292.         [inspectorBox display];
  293.         firstLoad = NO;
  294.     }
  295.     [self refresh];
  296.     [[self preferencesPanel] orderFront:self];
  297.     return self;
  298. }
  299.  
  300. - refresh    // refresh all controls -- set them to display the current state
  301. {
  302.     [speedButtons selectCellWithTag:speed];
  303.     [musicButtons selectCellWithTag:music];
  304.     [effectButtons selectCellWithTag:effects];
  305.     [levelText setIntValue:level];
  306.     [levelSlider setIntValue:level];
  307.     [alertSwitch setState:alert];
  308.     [borderSwitch setState:border];
  309.     [serverButton setState:useServer];
  310.     [serverText setStringValue:serverName];
  311.     [autoStartSwitch setState:autoStart];
  312.     [autoUnPauseSwitch setState:autoUnPause];
  313.     [demoSwitch setState:demoSound];
  314.     [keyMatrix sendAction:@selector(findKeyFor:) to:self forAllCells:YES];
  315.     return self;
  316. }
  317.  
  318. //
  319. // Methods to handle inspectors and swapping views around...
  320. //     (Very much adapted from NewInspector.m)
  321. //
  322.  
  323. - free
  324. {
  325.     [ViewsList free];
  326.     [preferencesPanel orderOut:self];
  327.     return [super free];
  328. }
  329.  
  330. - addView:(id)aView withName:(const char *)name
  331. {
  332.     [ViewsList addObject:aView];
  333.     [thePopUpList addItem:name];
  334.     return self;
  335. }
  336.  
  337. - show:(const char *)name
  338. {
  339.     [self turnOnView:[thePopUpList indexOfItem:name]];
  340.     [thePopUpListButton setTitle:name];
  341.     return self;
  342. }
  343.  
  344. - toggleInspectorPanels:sender
  345. {    // from pop-up list; we display the appropriate view.
  346.     return [self turnOnView:[sender selectedRow]];
  347. }
  348.  
  349. - turnOnView:(int)i
  350. {
  351.     NXRect newFrame;
  352.     
  353.     [preferencesPanel disableFlushWindow];
  354.     // get the right view
  355.     [inspectorBox setContentView:[ViewsList objectAt:i]];
  356.     
  357.     // resize and move to the right place
  358.     newFrame.size.width = view[i].size.width;
  359.     newFrame.size.height = view[i].size.height;
  360.     newFrame.origin.x = inspectFrame.origin.x +
  361.         (inspectFrame.size.width - view[i].size.width)/2;
  362.     newFrame.origin.y = inspectFrame.origin.y +
  363.         (inspectFrame.size.height - view[i].size.height)/2;
  364.     [inspectorBox setFrameFromContentFrame:&newFrame];
  365.     
  366.     // erase junk around it -- this wouldn't be necessary if I
  367.     // properly added/removed the Views from the respective hierarchies.
  368.     // sometime I'll get around to fixing this.
  369.     newFrame.size.width = view[i].size.width;
  370.     newFrame.size.height = view[i].size.height;
  371.     newFrame.origin.x = inspectFrame.origin.x +
  372.         (inspectFrame.size.width - view[i].size.width)/2;
  373.     newFrame.origin.y = inspectFrame.origin.y +
  374.         (inspectFrame.size.height - view[i].size.height)/2;
  375.     [grayView aroundFrame:&newFrame :inspectFrame.origin.y];
  376.     
  377.     // finally, display the new view
  378.     [inspectorBox display];
  379.     [self refresh];
  380.     [preferencesPanel reenableFlushWindow];
  381.     [preferencesPanel flushWindowIfNeeded];
  382.     return self;
  383. }
  384.  
  385. - preferencesPanel    // return the preferencesPanel, load it if needed.
  386. {
  387.     if( !preferencesPanel) {
  388.         [NXApp loadNibSection:"PreferencesPanel.nib" owner:self withNames:NO];
  389.         [preferencesPanel setFrameUsingName:"Prefs"];
  390.         [preferencesPanel setFrameAutosaveName:"Prefs"];
  391.     }
  392.     return preferencesPanel;
  393. }
  394.  
  395. - musicChange:sender        // turn music on/off
  396. {
  397.     music = [[sender selectedCell] tag];
  398.     // music runs independently, so we just turn it on or off at the
  399.     // appropriate times.  *****Maybe I should have the score playback
  400.     // pause when you pause a game; right now it doesn't.
  401. #ifdef GK_USE_MUSICKIT
  402.     if ((music) && ([gameScreen gameState] != GAMEOVER))
  403.         [scorePlayer play:self];
  404.     else [scorePlayer stop:self];
  405. #endif
  406.     return self;
  407. }
  408.  
  409. - setScore:sender
  410. {    // sent by "Set Score File..." button; we forward to the ScorePlayer
  411. #ifdef GK_USE_MUSICKIT
  412.     [scorePlayer selectFile:sender];
  413. #endif
  414.     return self;
  415. }
  416.  
  417. - effectsChange:sender        // turn sound effects on/off
  418. {
  419.     effects = [[sender selectedCell] tag];
  420.     [soundPlayer turnOn:effects];
  421.     return self;
  422. }
  423.  
  424. - setDefaultPlayerName:(const char *)aString    // change default player name
  425. {
  426.     if (aString) [defaultPlayerName setStringValue:aString];
  427.     else [defaultPlayerName setStringValue:"Mystery Player"];
  428.     return self;
  429. }
  430.  
  431. - (const char *)defaultPlayerName  // return ptr to defaultPlayerName string
  432. {
  433.     return [defaultPlayerName stringValue];
  434. }
  435.  
  436. - alertChange:sender
  437. {
  438.     alert = NO;
  439.     if ([sender state]) alert = YES;
  440.     return self;
  441. }
  442.  
  443. - unPauseChange:sender
  444. {
  445.     autoUnPause = NO;
  446.     if ([sender state]) autoUnPause = YES;
  447.     return self;
  448. }
  449.  
  450. - autoStartChange:sender
  451. {
  452.     autoStart = NO;
  453.     if ([sender state]) autoStart = YES;
  454.     return self;
  455. }
  456.  
  457. - demoSoundChange:sender    // New turn off sound only in demo
  458. {
  459.     demoSound = NO;
  460.     if ([sender state]) demoSound = YES;
  461.     return self;
  462. }
  463.  
  464. - setBack:sender        // set the background image
  465. { // forward the message to the game screen
  466.     return [gameScreen changeBackground:sender];
  467. }
  468.  
  469. - revertBack:sender        // revert to default background image
  470. { // forward the message to the game screen
  471.     return [gameScreen revertBackground:sender];
  472. }
  473.  
  474. - (BOOL)borderOn { return border; }
  475. - setBorder:(BOOL)newBord
  476. {   // turn gray border on/off
  477.     if (border == newBord) return self;
  478.     border = newBord;
  479.     [gameScreen changeBorder:border]; // inform the GameView to adjust things.
  480.     return self;
  481. }
  482.  
  483. - borderChange:sender
  484. {   // turn gray border on/off -- sent by control on the panel
  485.     // this is a cover for the above method
  486.     return [self setBorder:[sender state]];
  487. }
  488.  
  489. - setUseServer:(BOOL)useIt
  490. {    // This allows the high score controlling object to turn things off
  491.     // if it can't connect or it loses the connection to the server
  492.     useServer = useIt;
  493.     [serverButton setState:useIt];
  494.     return [self refresh];
  495. }
  496.  
  497. - changeServer:sender
  498. {    // The main if block handles the button/check box, while the else
  499.     // block handles changing the server name (and also automatically
  500.     // checks the server box)
  501.     if (sender != serverText) { // user changed the button state
  502.         BOOL newUse = NO;
  503.         // get the state of the check box
  504.         if ([serverButton state]) newUse = YES;
  505.         if (useServer != newUse) { // turn local on/off
  506.             // attempt to connect to the servers if we aren't already
  507.             // note that this call only will happen if we're going local
  508.             // to network; if going the other way, we're already connected
  509.             // so we pass through...
  510.             if (![highScoreTable connected]) [highScoreTable connectToServers];
  511.             // before finishing, make sure there were no problems connecting;
  512.             // we can't assume all is OK.  (The -connected handles that; the
  513.             // 0 is in the case of going to a local table...)
  514.             useServer = (newUse ? [highScoreTable connected] : 0);
  515.             [highScoreTable setLocalScores:!useServer];
  516.         }
  517.     } else {
  518.         // check to see if the name is changing
  519.         if (strcmp(serverName, [serverText stringValue])) {
  520.             // make note of the new name (it has changed)
  521.             if (serverName) free(serverName);
  522.             serverName = NXCopyStringBufferFromZone([serverText stringValue],
  523.                     [self zone]);
  524.             [highScoreTable setServerHost:serverName];
  525.             // close current servers if already connected
  526.             // because we need to switch to a different server
  527.             if ([highScoreTable connected]) [highScoreTable closeServers];
  528.         }
  529.         // force us to use the server (i.e. return in server field will cause
  530.         // the check box to be checked automatically, enabling the server.)
  531.         useServer = YES;
  532.         [serverButton setState:useServer];
  533.         if (![highScoreTable connected]) [highScoreTable connectToServers];
  534.         // refresh the high score panel amongst other things.
  535.         [highScoreTable setLocalScores:![highScoreTable connected]];
  536.     }
  537.     // Note that if we couldn't locate the server, we go local.
  538.     // (The HighScoreController did that automatically for us above.)
  539.     // Finally, refresh the prefs panel to reflect any changes of internal
  540.     // state, in particular the state of the check box, which may have
  541.     // changed due to what happened above.  (No connection, etc.)
  542.     [self refresh];
  543.     return self;
  544. }
  545.  
  546. // if the Prefs are "unfair" then a game cannot be saved on a network server.
  547. // it is up to you to add methods that set unfair when the prefs become
  548. // unfair.  Also, in -startingGame, you should set unfair if any prefs are
  549. // unfair to begin with.  As it stands here, any game is fair...  Note that
  550. // the only way to clear the unfair variable is by starting a new game with
  551. // fair prefs; once a pref is made unfair, the game is unfair even if you
  552. // change it back.
  553. - (BOOL)unfair { return unfair; }
  554. - setUnfair { unfair = YES; return self; }
  555. - startingGame    // reset the unfair variable
  556. {
  557.     unfair = NO;
  558.     return self;
  559. }
  560.  
  561.  
  562. @end
  563.